// OGoMojo
// Whitemice.MOGI.Utilities.LDAPAccountSync
// License: LGPL
// Copyright: Whitemice Consulting, 2006
// Author(s): Adam Tauno Williams (awilliam@whitemice.org)
using System;
using System.Net;
using System.Collections;
using System.Threading;
using log4net;
using System.DirectoryServices;
using Whitemice.MOGI;
using Whitemice.MOGI.RPC2;

[assembly: log4net.Config.XmlConfigurator(ConfigFileExtension="log4net",Watch=true)]
namespace Whitemice.MOGI.Utilities 
{
	public class LDAPAccountSync
	{
		Whitemice.MOGI.RPC2.Server				server;
		DirectoryEntry							root;
		DirectorySearcher						search;

		public static void Main(string[] args)
		{
			new LDAPAccountSync();
		}
	
		public LDAPAccountSync()
		{
			server = new RPC2.Server("LDAPAccountSync"); 
			server.Hostname = server.GetDirectiveValue("LDAPAccountSync", "Hostname");
			server.Credentials = new NetworkCredential(
				server.GetDirectiveValue("LDAPAccountSync", "Username"),
				server.GetDirectiveValue("LDAPAccountSync", "Secret"));
			if (!server.Connected)
			{
				server.Log.Fatal("Unable to connect to groupware server");
				Thread.CurrentThread.Abort();
			}
			server.Log.Debug("LDAP account name attribute is " + server.GetDirectiveValue("LDAPAccountSync", "LoginAttribute"));
			server.Log.Debug("Performing LDAP search...");
			root = new DirectoryEntry();
			root.AuthenticationType = AuthenticationTypes.None;
			root.Username = server.GetDirectiveValue("LDAPAccountSync", "BindDN");
			root.Password = server.GetDirectiveValue("LDAPAccountSync", "BindSecret");
			root.Path = @"LDAP://" +
				server.GetDirectiveValue("LDAPAccountSync", "DSA") + "/" +
				server.GetDirectiveValue("LDAPAccountSync", "Base");
			search = new DirectorySearcher(root);
			search.Filter = server.GetDirectiveValue("LDAPAccountSync", "Filter");
			foreach(System.DirectoryServices.SearchResult user in search.FindAll())
			{
				ArrayList ogoResults;
				IAccount	account;
				
				server.Log.Debug("LDAP Object: " + user.Path + 
					"(Login=" + 
					(string)user.Properties[server.GetDirectiveValue("LDAPAccountSync", "LoginAttribute")][0] +
					")");
				ogoResults = null;
				server.Log.Debug("Seaching for OpenGroupware account...");
				ogoResults = server.Search("Document/Account/login=" +
					(string)user.Properties[server.GetDirectiveValue("LDAPAccountSync", "LoginAttribute")][0]);
				if (ogoResults.Count == 0)
					{
						server.Log.Debug("No such OGo account.");
						if (server.GetDirectiveValue("LDAPAccountSync", "CreateEnabled") == "true")
						{
							server.Log.Debug("Creating Account...");
							account = (IAccount)server.Get("Document/Account/0");
							account.Login = (string)user.Properties[server.GetDirectiveValue("LDAPAccountSync", "LoginAttribute")][0];
							server.Put(account);
							UpdatePerson("Document/Contact/" + MOGI.Id(account.Name), user);
						}
					} else 
						{
							account = (IAccount)ogoResults[0];
							server.Log.Debug("OGo Account: " + account.Name);
							if (server.GetDirectiveValue("LDAPAccountSync", "UpdateEnabled") == "true")
							{
								server.Log.Debug("Updating contact information...");
								UpdatePerson("Document/Contact/" + MOGI.Id(account.Name), user);
							} else server.Log.Debug("Update of contact information disabled.");
						}
			}
			root.Close();
		}
		
		protected void UpdatePerson(string name, System.DirectoryServices.SearchResult user)
		{
			IContact	contact;
			string		mapping;
			
			server.Log.Debug("  ...Getting contact information");
			contact = (IContact)server.Get(name);
			if (contact == null)
				return;
			mapping = server.GetDirectiveValue("LDAPAccountSync","AttributeMap");
			if (mapping == null)
				return;
			foreach(string pair in mapping.Split(','))
			{
				string[] side = pair.Split('=');
				switch(side.Length)
				{
					case 2:
						if(user.Properties.Contains(side[1]))
							switch(side[0])
							{
								case "FirstName":
									server.Log.Debug("  ...Updating FirstName property");
									contact.FirstName = (string)user.Properties[side[1]][0];
									break;
								case "MiddleName":
									server.Log.Debug("  ...Updating MiddleName property");
									contact.MiddleName = (string)user.Properties[side[1]][0];
									break;										
								case "LastName":
									server.Log.Debug("  ...Updating LastName property");
									contact.LastName = (string)user.Properties[side[1]][0];
									break;										
								case "BirthDate":
									server.Log.Debug("  ...Updating Birthdate property");
									if (((string)user.Properties[side[1]][0]).LastIndexOf('/') > 0)
										contact.BirthDate = Convert.ToDateTime((string)user.Properties[side[1]][0]).ToUniversalTime();
										else contact.BirthDate = Convert.ToDateTime((string)user.Properties[side[1]][0]).ToUniversalTime(); 
									break;										
								case "Comment":
									server.Log.Debug("  ...Updating Comment property");
									contact.Comment = (string)user.Properties[side[1]][0];
									break;										
								case "Email1":
									server.Log.Debug("  ...Updating Email1 property");
									contact.Email1 = (string)user.Properties[side[1]][0];
									break;										
								case "Email2":
									server.Log.Debug("  ...Updating Email2 property");
									contact.Email2 = (string)user.Properties[side[1]][0];
									break;										
								case "Email3":
									Console.WriteLine("  ...Updating Email3 property");
									contact.Email3 = (string)user.Properties[side[1]][0];
									break;										
								case "JobTitle":
									server.Log.Debug("  ...Updating JobTitle property");
									contact.JobTitle = (string)user.Properties[side[1]][0];
									break;										
								case "OtherTitle1":
									server.Log.Debug("  ...Updating OtherTitle1 property");
									contact.OtherTitle1 = (string)user.Properties[side[1]][0];
									break;									
								case "OtherTitle2":
									server.Log.Debug("  ...Updating OtherTitle2 property");
									contact.OtherTitle2 = (string)user.Properties[side[1]][0];
									break;
						}
						break;
					case 3:
						switch(side[0])
						{
							case "Phone":
								server.Log.Debug("  ...Updating Phone number " + side[1]);
								if (contact.HasPhoneType(side[1]))
									if (user.Properties.Contains(side[2]))
										contact.PhoneNumber(side[1]).DialNumber = 
											(string)user.Properties[side[2]][0];
								break;
							case "Address":
							case "XA":
								break;
						}
						break;
					}
			}
			server.Log.Debug("  ...Writing object to the server (" +  contact.Name + ")");
			server.Put(contact);
		}
	}
}